/**
 * 一锅端：https://www.imooc.com/article/19204
 * @description: 网页授权获取用户资料
 * @author: junyong.hong
 * @createTime: 2018/11/18
 * @version: 1.0.0.0
 * @history:
 *    1、
 *    2、
 *
 */
// 1. 用户访问网页 /a
// 2. 服务器构建二跳网页地址 /b?state&appid 各种参数追加
// 3. 跳到微信授权页，用户主动授权，跳回来到 /a?code
// 4. 通过 code 换取 token code => wechat => access_token, openid
// 5. 通过 token + openid 换取资料 access_token => 用户资料

// 我把微信里的授权流程简单描述下：
//
// 用户在微信中打开你的网址 A
// 你在服务器里面偷换下给他重定向到网址 B
// 用户眼睁睁看着 B 网址展现一个是否同意授权的按钮
// 用户闭眼按下去，网址 B 跳到了 网址 C
// 你在服务器里面拿到了网址 C 上面的 code
// 你在服务器里面拿着 code 和 公众号 id/secret 拼了个网址 D
// 你在服务器里面请求网址 D 要回来 access_token 和 openID
// 你在服务器里面拿着 openID 去请求用户资料


const request = require('request-promise')

const base = 'https://api.weixin.qq.com/sns/'
const api = {
    // 引导关注者打开如下页面
    authorize: 'https://open.weixin.qq.com/connect/oauth2/authorize?',
    // 通过code换取网页授权access_token
    accessToken: base + 'oauth2/access_token?',
    // 拉取用户信息（需scope为snsapi_userinfo）
    userInfo: base + 'userinfo?'
}

module.exports = class WechatOAuth {
    constructor (opts) {
        this.appID = opts.appId
        this.appSecret = opts.appSecret
    }

    /**
     * 发送请求的方法
     * @returns {Promise.<void>}
     */
    async request (options) {
        options = Object.assign({}, options, {
            json: true
        })

        try {
            // 借助request-promise发出请求
            const res = await request(options)

            return res
        } catch (err) {
            console.log(err)
        }
    }

    /**
     * 1、二跳地址
     * 详细信息/主动授权：snsapi_userinfo
     * 基本信息/静默授权：snsapi_base
     * @param scope
     * @param target 跳转到的页面
     * @param state
     * @returns {string}
     */
    getAuthorizeURL (scope = 'snsapi_base', target, state) {
        const url = `${api.authorize}appid=${this.appID}&redirect_uri=${encodeURIComponent(target)}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`

        return url
    }

    /**
     * 2、获取accessToken
     * @param code
     * @returns {Promise.<void>}
     */
    async fetchAccessToken (code) {
        const url = `${api.accessToken}appid=${this.appID}&secret=${this.appSecret}&code=${code}&grant_type=authorization_code`

        const res = await this.request({ url })

        return res
    }

    /**
     * 3、获取用户信息
     * @param token
     * @param openID
     * @param lang
     * @returns {Promise.<void>}
     */
    async getUserInfo (token, openID, lang = 'zh_CN') {
        const url = `${api.userInfo}access_token=${token}&openid=${openID}&lang=${lang}`

        const res = await this.request({ url })

        return res
    }
}